package com.newland.starpos.partner.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.newland.starpos.partner.bean.UserInfo;
import com.newland.starpos.partner.bean.dto.PasswordDTO;
import com.newland.starpos.partner.bean.dto.ReceiverDTO;
import com.newland.starpos.partner.bean.dto.UserBankCardDTO;
import com.newland.starpos.partner.bean.dto.UserIdentityDTO;
import com.newland.starpos.partner.bean.po.*;
import com.newland.starpos.partner.bean.vo.RecevierVO;
import com.newland.starpos.partner.bean.vo.RemainTimeVO;
import com.newland.starpos.partner.exception.CustomException;
import com.newland.starpos.partner.http.ExceptionCodeEnum;
import com.newland.starpos.partner.http.ResponseEnum;
import com.newland.starpos.partner.http.ResponseModel;
import com.newland.starpos.partner.mapper.UserMapper;
import com.newland.starpos.partner.service.function.RedisCache;
import com.newland.starpos.partner.service.remote.GatewayService;
import com.newland.starpos.partner.service.remote.PortalService;
import com.newland.starpos.partner.thread.UserThreadLocal;
import com.newland.starpos.partner.utils.BeanUtils;
import com.newland.starpos.partner.utils.HttpUtils;
import com.newland.starpos.partner.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserInfoService {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private UserService userService;
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private GatewayService gatewayService;
    @Autowired
    private PortalService portalService;
    @Autowired
    private AuthCodeService authCodeService;

    static final String VALIDATE_ERR_TIMES = "PT_50007_";
    public static final int MAX_ERROR_TIMES = 3;

    // 根据userid查询是否已实名认证和银行卡已绑定
    @Transactional(readOnly = true)
    public ResponseModel queryCertificate() {
        Long userId = UserThreadLocal.get().getUserId();
        JSONObject data = new JSONObject() {{
            put("authinfomation", "1");// (0:已认证 1:未认证)
            put("bankinfomation", "1");// (0:已绑定 1:未绑定)
        }};
        User user = userMapper.selectById(userId);
        // 根据userId查询认证信息
        UserIdentity identity = userMapper.findIdentity(userId);
        if (Objects.nonNull(identity)) {// 该用户信息已认证
            data.put("authinfomation", "0");
            data.put("userName", user.getUserName());// 用户名
            data.put("identityName", identity.getName());
            data.put("identityCard", identity.getCardNo());
            data.put("identityType", identity.getType());
        }
        // 根据userId查询银行卡绑定信息，确认是否绑定
        BankCard bankCard = userMapper.findBCBind(userId);
        if (Objects.nonNull(bankCard)) {
            String bankName = bankCard.getBankName();
            data.put("bankinfomation", "0");// (0:已绑定 1:未绑定)
            data.put("userName", user.getUserName());// 用户名
            data.put("bankName", bankName);
            data.put("bankCard", bankCard.getBankCard());
            // (0:未识别)(1:已识别)
            data.put("unidentified", StringUtils.isBlank(bankName) ? "0" : "1");
        }
        return new ResponseModel(ResponseEnum.OK, data);
    }

    /**
     * 实名认证
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseModel authRealName(UserIdentityDTO userIdentityDTO, HttpServletRequest request) throws CustomException {

        Long userId = UserThreadLocal.get().getUserId();

        String iCardNo = userIdentityDTO.getICardNo();// 身份证号
        String iName = userIdentityDTO.getIName();// 用户真实姓名
        String bCardNo = userIdentityDTO.getBCardNo();// 银行卡号

        String token = request.getHeader("ACCESS_TOKEN");

        JSONObject data = new JSONObject();
        // 根据银行卡和身份证调用收单进行认证信息
        String result = gatewayService.readNameAuth(bCardNo, iCardNo, iName, token);
        if (!StringUtils.equals(result, "SUCCESS")) {
            return new ResponseModel(ResponseEnum.ERROR_USER_INFORMATION.code(), result);
        }

        UserIdentity identity = userMapper.findIdentity(userId);
        if (Objects.isNull(identity)) {
            identity = new UserIdentity();
            identity.setUserId(userId);
            identity.setType(1);// 凭证类型(1:身份证 2:港澳通行证)
            identity.setCardNo(iCardNo);// 身份证号
            identity.setName(iName);// 用户真实姓名
            userMapper.insertIdentity(identity);
        }
        // 根据bnk_acnm查询银行卡属于什么银行
        data.put("unidentified", "0");// (0:未识别)
        String bName = userMapper.findBName(bCardNo);
        if (StringUtils.isNotBlank(bName)) {
            data.put("unidentified", "1");// (1:已识别)
            data.put("bankName", bName);// 银行卡名称
        }

        // 根据userId查询银行卡绑定信息，确认是否绑定
        BankCard bankCard = userMapper.findBCBind(userId);
        if (Objects.isNull(bankCard)) {
            bankCard = new BankCard();
            bankCard.setUserId(userId);
            bankCard.setBankCard(bCardNo);// 银行卡卡号
            bankCard.setBankName(bName);// 银行名称
            bankCard.setStatus(1);// 绑定
            userMapper.insertBCard(bankCard);
        } else {
            data.put("bankinfomation", "0");// (0:已绑定 1:未绑定)
        }
        return new ResponseModel(ResponseEnum.OK, data);
    }

    /**
     * 绑定和解绑银行卡信息查询
     */
    @Transactional
    @SuppressWarnings({"rawtypes"})
    public ResponseModel bindOrUnbind(UserBankCardDTO userBankCardDTO, HttpServletRequest request)
            throws CustomException {

        Long userId = UserThreadLocal.get().getUserId();
        String bCardNo = userBankCardDTO.getBankCard();
        String status = userBankCardDTO.getStatus();

        BankCard bankCard = userMapper.findBCBind(userId);
        switch (status){// (1:绑定 2:解绑)
            case "1":{
                if(Objects.nonNull(bankCard)){
                    throw new CustomException(50011, "请先解绑再绑定新卡");
                }
                // 根据userId查询认证信息，确认是否已认证
                UserIdentity identity = userMapper.findIdentity(userId);
                if (Objects.isNull(identity)) {
                    log.error("用户还未实名认证,请先实名认证");
                    throw new CustomException(ResponseEnum.DATA_NOT_FOUNT_REAL_NAME);
                }
                String iCardNo = identity.getCardNo();// 身份证号
                String iName = identity.getName();// 用户真实姓名

                // 根据银行卡和身份证调用收单进行认证信息
                String token = request.getHeader("ACCESS_TOKEN");

                // 根据银行卡和身份证调用收单进行认证信息
                String result = gatewayService.readNameAuth(bCardNo, iCardNo, iName, token);
                if (!StringUtils.equals(result, "SUCCESS")) {
                    return new ResponseModel(ResponseEnum.ERROR_USER_INFORMATION.code(), result);
                }
                String bName = userMapper.findBName(bCardNo);
                bankCard = new BankCard();
                bankCard.setUserId(userId);
                bankCard.setBankName(bName);// 银行卡归属银行
                bankCard.setBankCard(bCardNo);// 银行卡卡号
                bankCard.setStatus(1);// 绑定
                userMapper.insertBCard(bankCard);
                break;
            }
            case "2":{
                if(Objects.nonNull(bankCard)){
                    bankCard.setStatus(2);
                    userMapper.updateBCard(bankCard);
                }
                break;
            }
            default:
                throw new CustomException(50010, "绑定/解绑操作未知");
        }
        return new ResponseModel(ResponseEnum.OK);
    }

    /**
     * 登陆密码修改
     */
    @SuppressWarnings({"rawtypes"})
    public ResponseModel modifyPassword(PasswordDTO passwordDTO, HttpServletRequest request)
            throws CustomException {

        Long userId = UserThreadLocal.get().getUserId();

        String logPassword = passwordDTO.getLogPassword();// 原始密码
        String newPassword = passwordDTO.getNewPassword();// 新密码
        String confirmedPassword = passwordDTO.getConfirmedPassword();// 确认新密码

        JSONObject data = new JSONObject();
        // 验证原始密码是否为空
        if (StringUtils.isBlank(logPassword)) {
            log.error("=== querylogResetPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_LOG_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_LOG_PWDISNULL);

        }
        // 验证新密码是否为空
        if (StringUtils.isBlank(newPassword)) {
            log.error("=== querylogResetPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_NEW_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_NEW_PWDISNULL);
        }

        // 确认新密码是否为空
        if (StringUtils.isBlank(confirmedPassword)) {
            log.error("=== querylogResetPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_CONFIRME_NEW_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_CONFIRME_NEW_PWDISNULL);
        }

        // 确认新密码和新密码输入是否一致
        if (!confirmedPassword.equals(newPassword)) {
            log.error("=== querylogResetPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_PWDISNULL);
        }
        User user = userMapper.selectById(userId);

        // 调用portal接口，通知修改密码相关信息推送给portal
        portalService.modifyPassword(user.getTelephone(), logPassword, newPassword, request);
        userService.UpdateUserPwType(user);
        return new ResponseModel(ResponseEnum.OK);
    }

    /**
     * 支付密码修改
     */
    @Transactional
    public ResponseModel modifyPayPassword(PasswordDTO passwordDTO) {
        Long userId = UserThreadLocal.get().getUserId();

        String payPassword = passwordDTO.getPaymentPassword();// 原支付密码
        String newPassword = passwordDTO.getNewPassword();// 新密码
        String confirmedPassword = passwordDTO.getConfirmedPassword();// 确认新密码

        // 验证原始支付密码是否为空
        if (StringUtils.isBlank(payPassword)) {
            log.error("=== querylogResetPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_PAYMENT_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_PAYMENT_PWDISNULL);
        }
        // 验证新密码是否为空
        if (StringUtils.isBlank(newPassword)) {
            log.error("=== querylogResetPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_NEW_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_NEW_PWDISNULL);
        }

        // 确认新密码是否为空
        if (StringUtils.isBlank(confirmedPassword)) {
            log.error("=== querylogResetPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_CONFIRME_NEW_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_CONFIRME_NEW_PWDISNULL);
        }

        // 确认新密码和新密码输入是否一致
        if (!confirmedPassword.equals(newPassword)) {
            log.error("=== querylogResetPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_PWDISNULL);
        }

        // 根据userId查询用户信息
        User user = userMapper.selectById(userId);
        String oldPayPassword = user.getPaymentPassword();

        if(StringUtils.isNotBlank(oldPayPassword) && !StringUtils.equals(oldPayPassword, payPassword)){
            return new ResponseModel(ResponseEnum.PAYMENT_PASSWORD);
        }else if (StringUtils.equals(oldPayPassword, newPassword)) {
            return new ResponseModel(ResponseEnum.PAYMENT_PASSWORD_NO_EQUAL);
        }
        user.setPaymentPassword(newPassword);
        userMapper.updateById(user);
        return new ResponseModel(ResponseEnum.OK);
    }

    // 支付密码通过手机短信修改
    @Transactional
    public ResponseModel resetPayPassword(PasswordDTO passwordDTO) throws CustomException {
        Long userId = UserThreadLocal.get().getUserId();

        String newPassword = passwordDTO.getNewPassword();// 新密码
        String confirmedPassword = passwordDTO.getConfirmedPassword();// 确认新密码

        // 验证码校验
        String authCode = passwordDTO.getAuthCode();
        if (StringUtils.isBlank(authCode)
                || !authCodeService.checkAuthCode(passwordDTO.getTelephone(), authCode)) {
            return new ResponseModel(ResponseEnum.SMS_CODE_ERROR);
        }
        User existUser = userMapper.findUserByPhone(passwordDTO.getTelephone());
        if (null == existUser) {
            return new ResponseModel(ResponseEnum.USER_NOT_EXIST);
        }

        // 验证新密码是否为空
        if (StringUtils.isBlank(newPassword)) {
            log.error("=== forgetPaymentPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_NEW_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_NEW_PWDISNULL);
        }

        // 确认新密码是否为空
        if (StringUtils.isBlank(confirmedPassword)) {
            log.error("=== forgetPaymentPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_CONFIRME_NEW_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_CONFIRME_NEW_PWDISNULL);
        }

        // 确认新密码和新密码输入是否一致
        if (!confirmedPassword.equals(newPassword)) {
            log.error("=== forgetPaymentPWD userPasswordDTO ：{}, {} ===", passwordDTO,
                    ResponseEnum.ERROR_NEW_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_PWDISNULL);
        }
        // 根据userId查询用户信息
        User user = userMapper.selectById(userId);
        user.setPaymentPassword(newPassword);
        userMapper.updateById(user);
        return new ResponseModel(ResponseEnum.OK);
    }

    // 在进入支付密码修改前先校验支付密码输入是否正确
    public ResponseModel queryvalidatepaymentPWD(PasswordDTO userPasswordDTO) {
        UserInfo credential = UserThreadLocal.get();
        Long userId = credential.getUserId();// 从拦截器获取userid
        String paymentPassword = userPasswordDTO.getPaymentPassword();// 原支付密码
        // 验证原始支付密码是否为空
        if (StringUtils.isBlank(paymentPassword)) {
            log.error("=== queryvalidatepaymentPWD userPasswordDTO ：{}, {} ===", userPasswordDTO,
                    ResponseEnum.ERROR_PAYMENT_PWDISNULL);
            return new ResponseModel(ResponseEnum.ERROR_PAYMENT_PWDISNULL);
        }
        // 根据userId查询用户信息
        User user = userMapper.selectById(userId);
        if (user != null) {
            if (paymentPassword.equals(user.getPaymentPassword())) {
                return new ResponseModel(ResponseEnum.OK);
            } else {
                log.error("=== querylogResetPWD userPasswordDTO ：{}, {} ===", userPasswordDTO,
                        ResponseEnum.PAYMENT_PASSWORD);
                return new ResponseModel(ResponseEnum.PAYMENT_PASSWORD);
            }
        } else {
            log.error("=== queryvalidatepaymentPWD userPasswordDTO ：{}, {} ===", userPasswordDTO,
                    ResponseEnum.USER_INFORMATION_ISNULL);
            return new ResponseModel(ResponseEnum.USER_INFORMATION_ISNULL);
        }
    }

    public ResponseModel validateCode(PasswordDTO userPasswordDTO) throws CustomException {

        String telephone = userPasswordDTO.getTelephone();

        if (StringUtils.isNotBlank(telephone)) {
            // 验证码校验
            String authCode = userPasswordDTO.getAuthCode();
            if (StringUtils.isBlank(authCode)
                    || !authCodeService.checkAuthCode(telephone, authCode)) {

                String key = VALIDATE_ERR_TIMES + telephone;
                String errorCount = redisCache.getString(key);
                if (StringUtils.isNotBlank(errorCount) && Integer.parseInt(errorCount) >= MAX_ERROR_TIMES) {
                    throw new CustomException(ResponseEnum.AUTHCODE_LOGIN_ERROR_TIMES_GT);
                }
                Long count = MAX_ERROR_TIMES - redisCache.increment(key, 1);
                redisCache.expire(key, 30, TimeUnit.MINUTES);
                throw new CustomException(ResponseEnum.AUTHCODE_ERROR_TIMES_GT, new RemainTimeVO(count));
            }
        } else {
            log.error("=== validateCode userPasswordDTO ：{}, {} ===", userPasswordDTO, ResponseEnum.PARAM_NULL);
            return new ResponseModel(ResponseEnum.PARAM_NULL);
        }
        return new ResponseModel(ResponseEnum.OK);
    }

    @SuppressWarnings("unused")
    @Transactional
    public ResponseModel queryUnidentifiedList(UserBankCardDTO userBankCardDTO) {
        Long userId = UserThreadLocal.get().getUserId();

        String bCardNO = userBankCardDTO.getBankCard();
        String bName = userBankCardDTO.getBankName();
        JSONObject data = new JSONObject();

        if (StringUtils.isNotBlank(bCardNO)) {
            // 根据userId查询认证信息，确认是否已认证
            UserIdentity identity = userMapper.findIdentity(userId);
            if (Objects.nonNull(identity)) {
                // 根据userId查询银行卡绑定信息，确认是否绑定
                BankCard bankCard = userMapper.findBCBind(userId);
                if (Objects.nonNull(bankCard)) {
                    bankCard.setUserId(userId);
                    bankCard.setBankName(bName);
                    userMapper.updateBCardName(bankCard);
                    return new ResponseModel(ResponseEnum.OK);
                } else {
                    data.put("bankinfomation", "1");// (0:已绑定 1:未绑定)
                    return new ResponseModel(ResponseEnum.OK, data);
                }
            } else {
                // 返回错误信息:未查到该用户认证信息,请先进行实名认证，在绑定银行卡
                return new ResponseModel(ResponseEnum.DATA_NOT_FOUNT_REAL_NAME);
            }
        } else {
            log.error("=== queryUnidentifiedList userBankCardDTO ：{}, {} ===", userBankCardDTO,
                    ResponseEnum.PARAM_NULL);
            return new ResponseModel(ResponseEnum.PARAM_NULL);
        }
    }

    /*public ResponseModel queryReceiver() {
        Long userId = UserThreadLocal.get().getUserId();
        List<UserReceivePO> receivers = receiverDao.queryReceiverByUserId(userId);
        log.info(String.format("find receiver by userId: %s, record count: %s", userId, receivers.size()));
        if (receivers.isEmpty()) {
            return new ResponseModel(ResponseEnum.RECEIVER_NOT_FONUD);
        }
        // 排序
        Collections.sort(receivers, new Comparator<UserReceivePO>() {
            @Override
            public int compare(UserReceivePO r1, UserReceivePO r2) {
                if (r1.getOrderTime().before(r2.getOrderTime())) {
                    return 1;
                }
                return -1;
            }

        });
        List<RecevierVO> responseData = BeanUtils.batchTransfrom(RecevierVO.class, receivers);
        return new ResponseModel(ResponseEnum.OK, responseData);
    }

    @Transactional
    public ResponseModel addOrModeReceiver(ReceiverDTO receiverDTO) throws CustomException {
        Long userId = UserThreadLocal.get().getUserId();
        Long receiveId = receiverDTO.getReceiveId();
        UserReceivePO userReceive;
        // 有收货ID为修改操作,没有则为新增操作
        Date now = new Date();
        if (receiveId != null) {
            userReceive = receiverDao.findById(receiveId, userId);
        } else {
            userReceive = new UserReceivePO();
            userReceive.setCreTime(now);
            userReceive.setUserId(userId);
        }
        if (userReceive == null)
            throw new CustomException(ResponseEnum.RECEIVER_NOT_FORMAT);

        Regional regional = userMapper.findRegionalByCode(receiverDTO.getRegionalCode());
        if (null == regional) {
            return new ResponseModel(ResponseEnum.REGIONAL_CODE_ERROR);
        }
        userReceive.setUpdTime(now);
        userReceive.setOrderTime(now);
        userReceive.location(regional);
        userReceive.receiverDTO(receiverDTO);
        receiverDao.saveOrUpdate(userReceive);
        RecevierVO recevierVo = BeanUtils.transfrom(RecevierVO.class, userReceive);

        return new ResponseModel(ResponseEnum.OK, recevierVo);
    }

    public ResponseModel queryGrade(HttpServletRequest request) {
        UserInfo credential = UserThreadLocal.get();
        Long userId = credential.getUserId();
        Map<String, Object> data = new HashMap<String, Object>();
        if (userId != null) {
            Grade grade = gradeDao.findGrade(userId);
            if (grade != null) {
                Integer level = grade.getMerGrade() + grade.getPartnerGrade() + grade.getTradeGrade()
                        + grade.getStartGrade();// 总等级
                if (level > 5) {
                    data.put("levels", "5");
                } else {
                    String levels = String.valueOf(level);
                    data.put("levels", levels);
                }
                return new ResponseModel(ResponseEnum.OK, data);
            } else {
                return new ResponseModel(ResponseEnum.LEVEL_ISNULL);
            }
        } else {
            return new ResponseModel(ResponseEnum.PARAM_NULL);
        }
    }*/

}
